home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Libraries / TurboTCP 2.0.1 / TurboTCP source / CTCPResolverCall.cp < prev    next >
Encoding:
Text File  |  1994-11-21  |  23.5 KB  |  910 lines  |  [TEXT/MPCC]

  1. /*
  2. ** CTCPResolverCall.cp
  3. **
  4. **    TurboTCP support library
  5. **    TCP resolver call class
  6. **
  7. **    Copyright © 1993-94, FrostByte Design / Eric Scouten
  8. **    Some portions adapted from file “dnr.c” Copyright © 1988 by Apple Computer. All rights reserved.
  9. **
  10. */
  11.  
  12.  
  13. #include "CTCPResolverCall.h"
  14.  
  15. #include <Folders.h>
  16. #include <GestaltEqu.h>
  17. #include <Traps.h>
  18. #include "OSChecks.h"
  19. #include "TCLUtilities.h"
  20. #include "CPtrArray.h"
  21.  
  22.  
  23. #ifndef TCL_NO_TEMPLATES
  24.     class CTCPResolverCallList : public CPtrArray<CTCPResolverCall> {};
  25. #else
  26.     TM_DECLARE_CPtrArray(CTCPResolverCall);
  27. #endif
  28.  
  29.  
  30. // procedure code numbers for DNR code segment
  31.  
  32. #define OPENRESOLVER    1L
  33. #define CLOSERESOLVER    2L
  34. #define STRTOADDR        3L
  35. #define ADDRTOSTR        4L
  36. #define ENUMCACHE        5L
  37. #define ADDRTONAME    6L
  38. #define HINFO            7L
  39. #define MXINFO            8L
  40.  
  41.  
  42. //    —— class variables ——
  43.  
  44. Handle            CTCPResolverCall::macDNRcode = NULL;
  45. UniversalProcPtr    CTCPResolverCall::macDNRentry = NULL;
  46. #if GENERATINGCFM
  47. ResultUPP            CTCPResolverCall::StrToAddrUPP = NewResultProc(CTCPResolverCall::PostponeStrToAddr);
  48. ResultUPP            CTCPResolverCall::AddrToNameUPP = NewResultProc(CTCPResolverCall::PostponeAddrToName);
  49. Result2UPP        CTCPResolverCall::HInfoUPP = NewResult2Proc(CTCPResolverCall::PostponeHInfo);
  50. Result2UPP        CTCPResolverCall::MXInfoUPP = NewResult2Proc(CTCPResolverCall::PostponeMXInfo);
  51. #endif
  52.  
  53.  
  54. TCL_DEFINE_CLASS_M0(CTCPResolverCall);
  55.  
  56.  
  57. /*______________________________________________________________________
  58. **
  59. ** interfaces to TCP DNR (adapted from latest <dnr.c>
  60. **
  61. */
  62.  
  63. // NOTE: The dnr.c file created for universal headers contained an error. All of the selectors
  64. // are treated by the DNR as long values, not short. This has been corrected in TurboTCP.
  65.  
  66. extern "C" {
  67.  
  68. typedef OSErr (*OpenResolverProcPtr)(long selector, char* fileName);
  69. typedef OSErr (*CloseResolverProcPtr)(long selector);
  70. typedef OSErr (*StrToAddrProcPtr)(long selector, char* hostName, struct hostInfo* rtnStruct,
  71.                                 long resultProc, char* userData);
  72. typedef OSErr (*AddrToStrProcPtr)(long selector, long address, char* hostName);
  73. typedef OSErr (*AddrToNameProcPtr)(long selector, unsigned long addr, struct hostInfo* rtnStruct,
  74.                                 long resultProc, char* userData);
  75. typedef OSErr (*HInfoProcPtr)(long selector, char* hostName, struct returnRec* returnRecPtr,
  76.                                 long resultProc, char* userData);
  77. typedef OSErr (*MXInfoProcPtr)(long selector, char* hostName, struct returnRec* returnRecPtr,
  78.                                 long resultProc, char* userData);
  79.  
  80. };
  81.  
  82. #if GENERATINGCFM
  83.  
  84. enum {
  85.     uppOpenResolverProcInfo = kCStackBased
  86.          | RESULT_SIZE(SIZE_CODE(sizeof(short)))
  87.          | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(long)))
  88.          | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(char*)))
  89. };
  90.  
  91. enum {
  92.     uppCloseResolverProcInfo = kCStackBased
  93.          | RESULT_SIZE(SIZE_CODE(sizeof(short)))
  94.          | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(long)))
  95. };
  96. enum {
  97.     uppStrToAddrProcInfo = kCStackBased
  98.          | RESULT_SIZE(SIZE_CODE(sizeof(short)))
  99.          | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(long)))
  100.          | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(char*)))
  101.          | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(struct hostInfo*)))
  102.          | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(long)))
  103.          | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(char*)))
  104. };
  105. enum {
  106.     uppAddrToStrProcInfo = kCStackBased
  107.          | RESULT_SIZE(SIZE_CODE(sizeof(short)))
  108.          | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(long)))
  109.          | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(unsigned long)))
  110.          | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(char*)))
  111. };
  112. enum {
  113.     uppAddrToNameProcInfo = kCStackBased
  114.          | RESULT_SIZE(SIZE_CODE(sizeof(short)))
  115.          | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(long)))
  116.          | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(unsigned long)))
  117.          | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(struct hostInfo*)))
  118.          | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(long)))
  119.          | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(char*)))
  120.  
  121. };
  122. enum {
  123.     uppHInfoProcInfo = kCStackBased
  124.          | RESULT_SIZE(SIZE_CODE(sizeof(short)))
  125.          | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(long)))
  126.          | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(char*)))
  127.          | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(struct returnRec*)))
  128.          | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(long)))
  129.          | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(char*)))
  130.  
  131. };
  132. enum {
  133.     uppMXInfoProcInfo = kCStackBased
  134.          | RESULT_SIZE(SIZE_CODE(sizeof(short)))
  135.          | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(long)))
  136.          | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(char*)))
  137.          | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(struct returnRec*)))
  138.          | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(long)))
  139.          | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(char*)))
  140.  
  141. };
  142.  
  143. typedef UniversalProcPtr OpenResolverUPP;
  144. typedef UniversalProcPtr CloseResolverUPP;
  145. typedef UniversalProcPtr StrToAddrUPP;
  146. typedef UniversalProcPtr AddrToStrUPP;
  147. typedef UniversalProcPtr AddrToNameUPP;
  148. typedef UniversalProcPtr HInfoUPP;
  149. typedef UniversalProcPtr MXInfoUPP;
  150.  
  151. #define    CallOpenResolverProc(userRoutine, selector, filename)    \
  152.         CallUniversalProc(userRoutine, uppOpenResolverProcInfo, selector, filename)
  153. #define    CallCloseResolverProc(userRoutine, selector)    \
  154.         CallUniversalProc(userRoutine, uppCloseResolverProcInfo, selector)
  155. #define    CallStrToAddrProc(userRoutine, selector, hostName, rtnStruct, resultProc, userData)    \
  156.         CallUniversalProc(userRoutine, uppStrToAddrProcInfo, selector, hostName, rtnStruct, resultProc, userData)
  157. #define    CallAddrToStrProc(userRoutine, selector, address, hostName)    \
  158.         CallUniversalProc(userRoutine, uppAddrToStrProcInfo, selector, address, hostName)
  159. #define    CallAddrToNameProc(userRoutine, selector, addr, rtnStruct, resultProc, userData)    \
  160.         CallUniversalProc(userRoutine, uppAddrToNameProcInfo, selector, addr, rtnStruct, resultProc, userData)
  161. #define    CallHInfoProc(userRoutine, selector, hostName, returnRecPtr, resultProc, userData)    \
  162.         CallUniversalProc(userRoutine, uppHInfoProcInfo, selector, hostName, returnRecPtr, resultProc, userData)
  163. #define    CallMXInfoProc(userRoutine, selector, hostName, returnRecPtr, resultProc, userData)    \
  164.         CallUniversalProc(userRoutine, selector, hostName, returnRecPtr, resultProc, userData)
  165.  
  166. #else // #if GENERATINGCFM
  167.  
  168. typedef OpenResolverProcPtr OpenResolverUPP;
  169. typedef CloseResolverProcPtr CloseResolverUPP;
  170. typedef StrToAddrProcPtr StrToAddrUPP;
  171. typedef AddrToStrProcPtr AddrToStrUPP;
  172. typedef AddrToNameProcPtr AddrToNameUPP;
  173. typedef HInfoProcPtr HInfoUPP;
  174. typedef MXInfoProcPtr MXInfoUPP;
  175.  
  176. #define    CallOpenResolverProc(userRoutine, selector, filename)    \
  177.         (*((OpenResolverProcPtr) userRoutine))(selector, filename)
  178. #define    CallCloseResolverProc(userRoutine, selector)    \
  179.         (*((CloseResolverProcPtr) userRoutine))(selector)
  180. #define    CallStrToAddrProc(userRoutine, selector, hostName, rtnStruct, resultProc, userData)    \
  181.         (*((StrToAddrProcPtr) userRoutine))(selector, hostName, rtnStruct, resultProc, userData)
  182. #define    CallAddrToStrProc(userRoutine, selector, address, hostName)    \
  183.         (*((AddrToStrProcPtr) userRoutine))(selector, address, hostName)
  184. #define    CallAddrToNameProc(userRoutine, selector, addr, rtnStruct, resultProc, userData)    \
  185.         (*((AddrToNameProcPtr) userRoutine))(selector, addr, rtnStruct, resultProc, userData)
  186. #define    CallHInfoProc(userRoutine, selector, hostName, returnRecPtr, resultProc, userData)    \
  187.         (*((HInfoProcPtr) userRoutine))(selector, hostName, returnRecPtr, resultProc, userData)
  188. #define    CallMXInfoProc(userRoutine, selector, hostName, returnRecPtr, resultProc, userData)    \
  189.         (*((MXInfoProcPtr) userRoutine))(selector, hostName, returnRecPtr, resultProc, userData)
  190.  
  191. #endif // #ifdef GENERATINGCFM
  192.  
  193.  
  194. //    —— constructor/destructor ——
  195.  
  196. /*______________________________________________________________________
  197. **
  198. ** constructor
  199. **
  200. **    Initialize the resolver object.
  201. **
  202. */
  203.  
  204. CTCPResolverCall::CTCPResolverCall(CTCPEndpoint& theEndpoint)
  205.     : itsEndpoint(&theEndpoint), qEntry(this)
  206.  
  207. {
  208.     // clear variables
  209.     
  210.     inUse = FALSE;
  211.     disposeOnCompletion = FALSE;
  212.     pendingNotify = notifNone;
  213.     qEntry.qType = resolverCall;
  214.     TCL_END_CONSTRUCTOR;
  215. }
  216.  
  217.  
  218. /*______________________________________________________________________
  219. **
  220. ** destructor
  221. **
  222. **    DO NOT CALL THIS METHOD! Use Dispose() instead.
  223. **
  224. */
  225.  
  226. CTCPResolverCall::~CTCPResolverCall()
  227. {
  228.     TCL_START_DESTRUCTOR;
  229. }
  230.  
  231.  
  232. /*______________________________________________________________________
  233. **
  234. ** Dispose
  235. **
  236. **    Get rid of the resolver object. If a resolver operation is in progress, will dispose of
  237. **    itself when the current resolver operation is completed.
  238. **
  239. **    Use Dispose() instead of destructor since the object may need to remain around for a
  240. **    while.
  241. **
  242. */
  243.  
  244. void CTCPResolverCall::Dispose()
  245.  
  246. {
  247.     if (inUse)
  248.         disposeOnCompletion = TRUE;
  249.     else
  250.         delete this;
  251. }
  252.  
  253.  
  254. //    —— initiate resolver calls ——
  255.  
  256. /*______________________________________________________________________
  257. **
  258. ** DoStrToAddr
  259. **
  260. **    Get the IP address of a host named by a DNS or dotted decimal string. Completion is
  261. **    handled by HandleStrToAddr.
  262. **
  263. **        theHostName (char*):    whose IP address do we need?
  264. **
  265. */
  266.  
  267. void CTCPResolverCall::DoStrToAddr(char* theHostName)
  268.  
  269. {
  270.     OSErr theResult;
  271.     
  272.     if (inUse)
  273.         FailOSErr(resolverInUse);
  274.     if (!(CTCPDriver::gTCPDriver)->CheckResolver())
  275.         FailOSErr(noResolverErr);
  276.     
  277.     inUse = TRUE;
  278.     (CTCPDriver::gTCPDriver)->RegisterActiveResolver(this);
  279.     BlockMove(theHostName, &hostName, 255);
  280.  
  281.     #if GENERATINGCFM                            // seems to be buggy here…
  282.         theResult = CallStrToAddrProc(macDNRentry, STRTOADDR, (char*) &hostName, &theHostInfo,
  283.                                 (long) StrToAddrUPP, (char*) this);
  284.     #else
  285.         theResult = CallStrToAddrProc(macDNRentry, STRTOADDR, (char*) &hostName, &theHostInfo,
  286.                                 (long) &PostponeStrToAddr, (char*) this);
  287.     #endif
  288.  
  289.  
  290.     // if call was completed immediately (with error or not), process it immediately
  291.     
  292.     if (theResult != cacheFault) {
  293.         inUse = FALSE;
  294.         (CTCPDriver::gTCPDriver)->RemoveActiveResolver(this);
  295.         HandleStrToAddr();
  296.     }
  297. }
  298.  
  299.  
  300. /*______________________________________________________________________
  301. **
  302. ** DoAddrToStr (static method)
  303. **
  304. **    Convert an IP address to dotted decimal notation. This call can be used while the resolver
  305. **    object is otherwise in use, and is completed immediately.
  306. **
  307. **        theIPaddr (ip_addr):    the address to convert
  308. **        theString (char*):    where to send the completed string (min. 16 chars)
  309. **
  310. */
  311.  
  312. void CTCPResolverCall::DoAddrToStr(ip_addr theIPaddr, char* theString)
  313.  
  314. {
  315.     if (!(CTCPDriver::gTCPDriver)->CheckResolver())
  316.         FailOSErr(noResolverErr);
  317.     CallAddrToStrProc(macDNRentry, ADDRTOSTR, theIPaddr, theString);
  318. }
  319.  
  320.  
  321. /*______________________________________________________________________
  322. **
  323. ** DoAddrToName
  324. **
  325. **    Get the canonical name of a host as specified by IP address. Completion is handled by
  326. **    HandleAddrToName method.
  327. **
  328. **        theIPaddr (ip_addr):    the IP address to query
  329. **
  330. */
  331.  
  332. void CTCPResolverCall::DoAddrToName(ip_addr theIPaddr)
  333.  
  334. {
  335.     OSErr theResult;
  336.     
  337.     if (inUse)
  338.         FailOSErr(resolverInUse);
  339.     if (!(CTCPDriver::gTCPDriver)->CheckResolver())
  340.         FailOSErr(noResolverErr);
  341.     
  342.     inUse = TRUE;
  343.     (CTCPDriver::gTCPDriver)->RegisterActiveResolver(this);
  344.  
  345.     #if GENERATINGCFM                            // seems to be buggy here…
  346.         theResult = CallAddrToNameProc(macDNRentry, ADDRTONAME, theIPaddr, &theHostInfo,
  347.                                     (long) AddrToNameUPP, (char*) this);
  348.     #else
  349.         theResult = CallAddrToNameProc(macDNRentry, ADDRTONAME, theIPaddr, &theHostInfo,
  350.                                     (long) &PostponeAddrToName, (char*) this);
  351.     #endif
  352.  
  353.  
  354.     // if call was completed immediately (with error or not), process it immediately
  355.     
  356.     if (theResult != cacheFault) {
  357.         inUse = FALSE;
  358.         (CTCPDriver::gTCPDriver)->RemoveActiveResolver(this);
  359.         HandleAddrToName();
  360.     }
  361. }
  362.  
  363.  
  364. /*______________________________________________________________________
  365. **
  366. ** DoHInfo
  367. **
  368. **    Get the CPU type and operating system type of a remote host. Completion is handled by
  369. **    HandleHInfo.
  370. **
  371. **        theHostName (char*):    who we askin’ ‘bout anyway?
  372. **
  373. */
  374.  
  375. void CTCPResolverCall::DoHInfo(char* theHostName)
  376.  
  377. {
  378.     OSErr theResult;
  379.     
  380.     if (inUse)
  381.         FailOSErr(resolverInUse);
  382.     if (!(CTCPDriver::gTCPDriver)->CheckResolver())
  383.         FailOSErr(noResolverErr);
  384.     
  385.     inUse = TRUE;
  386.     (CTCPDriver::gTCPDriver)->RegisterActiveResolver(this);
  387.     BlockMove(theHostName, &hostName, 255);
  388.  
  389.     #if GENERATINGCFM                            // seems to be buggy here…
  390.         theResult = CallHInfoProc(macDNRentry, HINFO, (char*) &hostName, &theHMXInfo,
  391.                                 (long) HInfoUPP, (char*) this);
  392.     #else
  393.         theResult = CallHInfoProc(macDNRentry, HINFO, (char*) &hostName, &theHMXInfo,
  394.                                 (long) &PostponeHInfo, (char*) this);
  395.     #endif
  396.  
  397.  
  398.     // if call was completed immediately (with error or not), process it immediately
  399.     
  400.     if (theResult != cacheFault) {
  401.         inUse = FALSE;
  402.         (CTCPDriver::gTCPDriver)->RemoveActiveResolver(this);
  403.         HandleHInfo();
  404.     }
  405. }
  406.  
  407.  
  408. /*______________________________________________________________________
  409. **
  410. ** DoMXInfo
  411. **
  412. **    Get the mailbox exchange (MX) info of a remote host. Completion is handled by
  413. **    HandleMXInfo.
  414. **
  415. **        theHostName (char*):    who we askin’ ‘bout anyway?
  416. **
  417. */
  418.  
  419. void CTCPResolverCall::DoMXInfo(char* theHostName)
  420.  
  421. {
  422.     OSErr theResult;
  423.     
  424.     if (inUse)
  425.         FailOSErr(resolverInUse);
  426.     if (!(CTCPDriver::gTCPDriver)->CheckResolver())
  427.         FailOSErr(noResolverErr);
  428.     
  429.     inUse = TRUE;
  430.     (CTCPDriver::gTCPDriver)->RegisterActiveResolver(this);
  431.     BlockMove(theHostName, &hostName, 255);
  432.     #if GENERATINGCFM                            // seems to be buggy here…
  433.         theResult = CallMXInfoProc(macDNRentry, MXINFO, (char*) &hostName, &theHMXInfo,
  434.                                 (long) MXInfoUPP, (char*) this);
  435.     #else
  436.         theResult = CallMXInfoProc(macDNRentry, MXINFO, (char*) &hostName, &theHMXInfo,
  437.                                 (long) &PostponeMXInfo, (char*) this);
  438.     #endif
  439.  
  440.  
  441.     // if call was completed immediately (with error or not), process it immediately
  442.     
  443.     if (theResult != cacheFault) {
  444.         inUse = FALSE;
  445.         (CTCPDriver::gTCPDriver)->RemoveActiveResolver(this);
  446.         HandleMXInfo();
  447.     }
  448. }
  449.  
  450.  
  451. //    —— respond to completion of resolver calls ——
  452.  
  453. /*______________________________________________________________________
  454. **
  455. ** ProcessNotify (private method)
  456. **
  457. **    Handles any notifications passed to the resolver. This routine is free of interrupt-level
  458. **    constraints.
  459. **
  460. */
  461.  
  462. void CTCPResolverCall::ProcessNotify(void)
  463.  
  464. {
  465.     // free this resolver object for future use
  466.     
  467.     (CTCPDriver::gTCPDriver)->RemoveActiveResolver(this);
  468.     inUse = FALSE;    
  469.     
  470.  
  471.     // dispatch notification to appropriate routine
  472.     
  473.     switch (pendingNotify) {
  474.         case notifStrToAddr:
  475.             HandleStrToAddr();
  476.             break;
  477.             
  478.         case notifAddrToName:
  479.             HandleAddrToName();
  480.             break;
  481.             
  482.         case notifHInfo:
  483.             HandleHInfo();
  484.             break;
  485.             
  486.         case notifMXInfo:
  487.             HandleMXInfo();
  488.     }
  489.     
  490.     
  491.     // if someone attempted to dispose this earlier, do it now
  492.     
  493.     if (disposeOnCompletion)
  494.         delete this;
  495.     
  496. }
  497.  
  498.  
  499. //    —— open/close TCP resolver ——
  500.  
  501. /*______________________________________________________________________
  502. **
  503. ** OpenResolver (private static method)
  504. **
  505. **    Find the MacTCP DNR code resource and read it. Save the location of the resolver resource
  506. **    for later use.
  507. **
  508. */
  509.  
  510. void CTCPResolverCall::OpenResolver()
  511.  
  512. {
  513.     short    vRefNum;
  514.     short    refnum;
  515.     long        dirID;
  516.     short    fRef;
  517.     OSErr    rc;
  518.     
  519.     
  520.     // is the resolver already there?
  521.     
  522.     if (macDNRentry)
  523.         return;
  524.  
  525.  
  526.     // open the MacTCP driver to get DNR resources
  527.  
  528.     TRY {
  529.         refnum = OpenTheDNR();
  530.     }
  531.     CATCH {
  532.         NO_PROPAGATE;                    // ignore failures since the resource may
  533.                                         // have been installed in the System file
  534.                                         // (if running on a Mac 512Ke)
  535.     }
  536.     ENDTRY;
  537.  
  538.  
  539.     // load the DNR resource package
  540.     
  541.     macDNRcode = GetIndResource('dnrp', 1);
  542.     FailNIL(macDNRcode);
  543.     DetachResource(macDNRcode);
  544.  
  545.     if (refnum != -1)
  546.         CloseResFile(refnum);
  547.  
  548.         
  549.     // lock the DNR resource since it cannot be relocated while opened
  550.  
  551.     MoveHHi(macDNRcode);
  552.     HLock(macDNRcode);
  553.     macDNRentry = (UniversalProcPtr) *macDNRcode;
  554.  
  555.  
  556.     // check for “hosts” file in System Folder (BRB)
  557.  
  558.     GetSystemFolder(&vRefNum, &dirID);
  559.     rc = HOpen(vRefNum, dirID, "\pHosts", fsRdPerm, &fRef);
  560.     switch (rc) {
  561.         case noErr:
  562.             FSClose(fRef);
  563.             break;
  564.             
  565.         case fnfErr:
  566.             if ((rc = HCreate(vRefNum, dirID, "\pHosts", 'ttxt', 'TEXT')) != noErr)
  567.                 ErrorAlert(rc, SpecifyMsg(1001, 1));
  568.             break;
  569.             
  570.         default:
  571.             break;
  572.     }
  573.  
  574.  
  575.     // ask the DNR resource to open the resolver
  576.  
  577.     rc = CallOpenResolverProc(macDNRentry, OPENRESOLVER, NULL);
  578.                                             // send it a null hosts file name
  579.     if (rc != noErr) {
  580.         HUnlock(macDNRcode);                    // problem with open resolver, flush DNR resource
  581.         DisposHandle(macDNRcode);
  582.         macDNRcode = NULL;
  583.         macDNRentry = NULL;
  584.         FailOSErr(rc);                            // signal failure of DNR
  585.     }
  586.  
  587. }
  588.  
  589.  
  590. /*______________________________________________________________________
  591. **
  592. ** CloseResolver (private static method)
  593. **
  594. **    Shut down the DNR code resource. Does nothing if the resolver was never loaded.
  595. **
  596. */
  597.  
  598. void CTCPResolverCall::CloseResolver()
  599.  
  600. {
  601.  
  602.     // ensure that we had a resolver to begin with
  603.     
  604.     if (macDNRentry == NULL)
  605.         return;
  606.  
  607.  
  608.     // call CloseResolver function in DNR
  609.  
  610.     CallCloseResolverProc(macDNRentry, CLOSERESOLVER);
  611.  
  612.  
  613.     // release the DNR code resource
  614.  
  615.     HUnlock(macDNRcode);
  616.     DisposHandle(macDNRcode);
  617.     macDNRcode = NULL;
  618.     macDNRentry = NULL;
  619.  
  620. }
  621.  
  622.  
  623. /*______________________________________________________________________
  624. **
  625. ** OpenTheDNR (private static method)
  626. **
  627. **    Search in several places for the MacTCP DNR code resource. Tries the Control Panels
  628. **    folder and the System folder.
  629. **
  630. **        return (short):    reference number to resource file
  631. **
  632. */
  633.  
  634. short CTCPResolverCall::OpenTheDNR()
  635.  
  636. {
  637.     short    refnum;
  638.     short    vRefNum;
  639.     long        dirID;
  640.     
  641.     
  642.     // first search Control Panels for MacTCP 1.1.x
  643.  
  644.     GetCPanelFolder(&vRefNum, &dirID);
  645.     refnum = SearchFolderForDNRP('cdev', 'ztcp', vRefNum, dirID);
  646.     if (refnum != -1)
  647.         return refnum;
  648.     
  649.     
  650.     // next search System Folder for MacTCP 1.0.x
  651.  
  652.     GetSystemFolder(&vRefNum, &dirID);
  653.     refnum = SearchFolderForDNRP('cdev', 'mtcp', vRefNum, dirID);
  654.     if (refnum != -1)
  655.         return refnum;
  656.  
  657.  
  658.     // finally, search Control Panels for MacTCP 1.0.x
  659.  
  660.     GetCPanelFolder(&vRefNum, &dirID);
  661.     refnum = SearchFolderForDNRP('cdev', 'mtcp', vRefNum, dirID);
  662.     if (refnum != -1)
  663.         return refnum;
  664.     
  665.     return -1;
  666.  
  667. }
  668.  
  669.  
  670. /*______________________________________________________________________
  671. **
  672. ** SearchFolderForDNRP (private static method)
  673. **
  674. **    Search a folder for files that might contain the 'dnrp' resource.
  675. **
  676. **        targetType (OSType):    file type that we are looking for
  677. **        targetCreator (OSType):    file creator    ""        ""
  678. **        vRefNum (short):        volume ref num
  679. **        dirID (long):            directory number on the volume
  680. **
  681. **        return (short):            the refnum of the file if found, -1 if not found
  682. **
  683. */
  684.  
  685. short CTCPResolverCall::SearchFolderForDNRP(long targetType, long targetCreator,
  686.                                     short vRefNum, long dirID)
  687.  
  688. {
  689.     HParamBlockRec    fi;
  690.     Str255            filename;
  691.     short            refnum;
  692.     
  693.     
  694.     // initialize our search mechanism
  695.     
  696.     fi.fileParam.ioCompletion = nil;
  697.     fi.fileParam.ioNamePtr = filename;
  698.     fi.fileParam.ioVRefNum = vRefNum;
  699.     fi.fileParam.ioDirID = dirID;
  700.     fi.fileParam.ioFDirIndex = 1;
  701.     
  702.     
  703.     // keep looking till we run out of files
  704.     
  705.     while (PBHGetFInfo(&fi, false) == noErr) {
  706.     
  707.         // scan the folder for files that match our type & creator
  708.  
  709.         if (fi.fileParam.ioFlFndrInfo.fdType == targetType &&
  710.             fi.fileParam.ioFlFndrInfo.fdCreator == targetCreator) {
  711.  
  712.             // type/creator match, look for the resource
  713.             
  714.             refnum = HOpenResFile(vRefNum, dirID, filename, fsRdPerm);
  715.             if (GetIndResource('dnrp', 1) == NULL)
  716.                 CloseResFile(refnum);
  717.             else
  718.                 return refnum;
  719.         }
  720.  
  721.         // no match or no resource, try next file in folder
  722.  
  723.         fi.fileParam.ioFDirIndex++;
  724.         fi.fileParam.ioDirID = dirID;                // PBHGetFInfo() clobbers ioDirID
  725.     }
  726.     
  727.     return -1;                                    // nothing found
  728.  
  729. }    
  730.  
  731.  
  732. /*______________________________________________________________________
  733. **
  734. ** GetSystemFolder (private static method)
  735. **
  736. **    Return the ID of the current system folder.
  737. **
  738. **        vRefNumP (short *):        returns volume ref number
  739. **        dirIDP (long *):            returns directory ID
  740. **
  741. */
  742.  
  743. void CTCPResolverCall::GetSystemFolder(short* vRefNumP, long* dirIDP)
  744.  
  745. {
  746.     SysEnvRec    info;
  747.     long            wdProcID;
  748.     
  749.     SysEnvirons(1, &info);
  750.     if (GetWDInfo(info.sysVRefNum, vRefNumP, dirIDP, &wdProcID) != noErr) {
  751.         *vRefNumP = 0;
  752.         *dirIDP = 0;
  753.     }
  754. }
  755.  
  756.  
  757. /*______________________________________________________________________
  758. **
  759. ** GetCPanelFolder (private static method)
  760. **
  761. **    Return the ID of the current “Control Panels” folder.
  762. **
  763. **        vRefNumP (short*):        returns volume ref number
  764. **        dirIDP (long*):            returns directory ID
  765. **
  766. */
  767.  
  768. void CTCPResolverCall::GetCPanelFolder(short* vRefNumP, long* dirIDP)
  769.  
  770. {
  771.     Boolean    hasFolderMgr = false;
  772.     long        feature;
  773.     
  774.     
  775.     // see if we have the Folder Manager available
  776.     
  777.     if (TrapAvailable((short) _Gestalt))
  778.         if (Gestalt(gestaltFindFolderAttr, &feature) == noErr)
  779.             hasFolderMgr = TRUE;
  780.  
  781.  
  782.     // if folder manager, use it; else return system folder
  783.         
  784.     if (!hasFolderMgr) {
  785.         GetSystemFolder(vRefNumP, dirIDP);
  786.         return;
  787.     }
  788.     else {
  789.         if (FindFolder(kOnSystemDisk, kControlPanelFolderType,
  790.                     kDontCreateFolder, vRefNumP, dirIDP) != noErr) {
  791.             *vRefNumP = 0;
  792.             *dirIDP = 0;
  793.         }
  794.     }
  795.  
  796. }
  797.  
  798.  
  799. /***********************************************************************
  800. ************************************************************************
  801. **
  802. **    INTERRUPT-LEVEL routines follow. These routines cannot make memory allocations, cannot make
  803. **    synchronous TCP calls, and cannot use the Think C profiler.
  804. **
  805. */
  806.  
  807. #ifndef __MWERKS__
  808. //#pragma options(!profile)
  809. #else
  810. #pragma profile off
  811. #endif
  812.  
  813.  
  814. //     —— interrupt-level methods: delay processing for non-interrupt status ——
  815.  
  816. /*______________________________________________________________________
  817. **
  818. ** PostponeNotify (private static method)
  819. **
  820. **    Respond to notification that a DNR call was completed. Delays processing of notification
  821. **    until the next net-event call. This method merely logs the kind of notification and adds this
  822. **    resolver to the list of resolvers to be processed next time through the event loop.
  823. **
  824. **        theNotifType (NotifType):    which resolver call was completed
  825. **
  826. */
  827.  
  828. void CTCPResolverCall::PostponeNotify(NotifType theNotifType)
  829.  
  830. {
  831.     pendingNotify = theNotifType;
  832.     Enqueue((QElemPtr) &qEntry, &((CTCPDriver::gTCPDriver)->asyncQueue));
  833. }
  834.  
  835.  
  836. /*______________________________________________________________________
  837. **
  838. ** PostponeStrToAddr (private static method)
  839. **
  840. **    Respond to notification that the StrToAddr call was completed.
  841. **
  842. **        hostInfoPtr (…):        pointer to the DNR data structure (ignored)
  843. **        userDataPtr (char*):    user data pointer (assumed to be CTCPResolver*)
  844. **
  845. */
  846.  
  847. pascal void CTCPResolverCall::PostponeStrToAddr(struct hostInfo* hostInfoPtr, char* userDataPtr)
  848.  
  849. {
  850.     if (userDataPtr)
  851.         ((CTCPResolverCall*) userDataPtr)->PostponeNotify(notifStrToAddr);
  852. }
  853.  
  854.  
  855. /*______________________________________________________________________
  856. **
  857. ** PostponeAddrToName (private static method)
  858. **
  859. **    Respond to notification that the AddrToName call was completed.
  860. **
  861. **        hostInfoPtr (…):        pointer to the DNR data structure (ignored)
  862. **        userDataPtr (char*):    user data pointer (assumed to be CTCPResolver*)
  863. **
  864. */
  865.  
  866. pascal void CTCPResolverCall::PostponeAddrToName(struct hostInfo* hostInfoPtr, char* userDataPtr)
  867.  
  868. {
  869.     if (userDataPtr)
  870.         ((CTCPResolverCall*) userDataPtr)->PostponeNotify(notifAddrToName);
  871. }
  872.  
  873.  
  874. /*______________________________________________________________________
  875. **
  876. ** PostponeHInfo (private static method)
  877. **
  878. **    Respond to notification that the HInfo call was completed.
  879. **
  880. **        hostInfoPtr (…):        pointer to the DNR data structure (ignored)
  881. **        userDataPtr (char *):    user data pointer (assumed to be CTCPResolver *)
  882. **
  883. */
  884.  
  885. pascal void CTCPResolverCall::PostponeHInfo(struct returnRec* returnRecPtr, char* userDataPtr)
  886.  
  887. {
  888.     if (userDataPtr)
  889.         ((CTCPResolverCall*) userDataPtr)->PostponeNotify(notifHInfo);
  890. }
  891.  
  892.  
  893. /*______________________________________________________________________
  894. **
  895. ** PostponeMXInfo (private static method)
  896. **
  897. **    Respond to notification that the MXInfo call was completed.
  898. **
  899. **        hostInfoPtr (…):        pointer to the DNR data structure (ignored)
  900. **        userDataPtr (char*):    user data pointer (assumed to be CTCPResolver*)
  901. **
  902. */
  903.  
  904. pascal void CTCPResolverCall::PostponeMXInfo(struct returnRec* returnRecPtr, char* userDataPtr)
  905.  
  906. {
  907.     if (userDataPtr)
  908.         ((CTCPResolverCall*) userDataPtr)->PostponeNotify(notifMXInfo);
  909. }
  910.